# -*- coding: utf-8 -*-
from . import (
    api_app,
    request,
    response,
    json,
    re
)

from anytree.resolver import (
    Resolver,
    ResolverError,
    ChildResolverError
)
from anytree.iterators import LevelOrderIter
from ...patches.anytree_resolver import PatchResolver

from ...database.models.folder import Folder


@api_app.route('/folder<:re:/?>', method=['POST'])
def create_folder():
    name = request.params.getunicode('name', default=None, encoding='utf-8')
    parent = request.params.get('parent', None)
    ret = None
    if bool(name):
        DBC = request.environ.pop('DBC')
        error = None
        data = None
        if parent is None:
            error, data = create_top_folder(DBC, name)
        else:
            mat = re.match(r'^[0-9a-f]{16}$', parent, re.IGNORECASE)
            if mat:
                error, data = create_children_folder(DBC, name, parent)
            else:
                ret = {
                    'error': 2,
                    'desc': '参数无效'
                }
        if ret is None:
            if error is None:
                ret = {
                    'error': 0,
                    'desc': None,
                    'data': data
                }
            else:
                ret = {
                    'error': 3,
                    'desc': error
                }
    else:
        ret = {
            'error': 1,
            'desc': '缺少目录名'
        }
    response.content_type = 'application/json'
    return json.dumps(ret)

@api_app.route('/folder<:re:/?>', method=['GET'])
def list_folder():
    DBC = request.environ.pop('DBC')
    ret = {}
    parent = request.params.get('parent', None)
    if parent is None:
        data = query_top_level(DBC)
        ret = {
            'error': 0,
            'desc': None,
            'data': data
        }
    else:
        mat = re.match(r'^[0-9a-f]{16}$', parent, re.IGNORECASE)
        if mat:
            data = query_children_level(DBC, parent)
            if data is None:
                ret = {
                    'error': 3,
                    'desc': 'not found'
                }
            else:
                ret = {
                    'error': 0,
                    'desc': None,
                    'data': data
                }
        else:
            ret = {
                'error': 2,
                'desc': '参数无效'
            }
    response.content_type = 'application/json'
    return json.dumps(ret)

@api_app.route('/folder<:re:/?>', method=['DELETE'])
def delete_folder():
    hex_id = request.params.get('id', None)
    ret = None
    if not hex_id is None:
        DBC = request.environ.pop('DBC')
        mat = re.match(r'^[0-9a-f]{16}$', hex_id, re.IGNORECASE)
        if mat:
            oid = Folder.id_hex2bin(hex_id)
            node = None
            try:
                node = DBC.connection.get(oid)
            except KeyError:
                pass
            if isinstance(node, Folder):
                tree_key = Folder.tree_key()
                tree_root = node.root
                if isinstance(node.parent, Folder):
                    node.parent._p_changed = True
                node.parent = None
                del node
                DBC.root[tree_key] = tree_root
                DBC.root[tree_key]._p_changed = True
                DBC.root._p_changed = True
                DBC.commit()
                # 需要调用 db.pack() 才会真的执行GC, 真的删除
                DBC.db.pack()
                ret = {
                    'error': 0,
                    'desc': '操作成功'
                }
            else:
                ret = {
                    'error': 3,
                    'desc': '目录不存在'
                }
        else:
            ret = {
                'error': 2,
                'desc': '参数无效'
            }
    else:
        ret = {
            'error': 1,
            'desc': '缺少参数'
        }
    response.content_type = 'application/json'
    return json.dumps(ret)

################################################################################
def query_top_level(db_client):
    '''获取顶级目录'''
    tree_key = Folder.tree_key()
    # 根目录(程序内部保留)
    tree_root = db_client.root[tree_key]
    # 根目录下的直接子目录
    nodes = tree_root.children
    # 对象转字典列表
    data = []
    for node in nodes:
        data.append(node.toDict())
    return data

def query_children_level(db_client, parent):
    '''获取子目录(顶级目录下的，需指定父级目录id)'''
    oid = Folder.id_hex2bin(parent)
    node = None
    try:
        # http://zodb.readthedocs.io/en/latest/api.html#transaction.IConnection.get
        node = db_client.connection.get(oid)
    except KeyError:
        pass
    if isinstance(node, Folder):
        # https://anytree.readthedocs.io/en/latest/apidoc/anytree.node.html#anytree.node.NodeMixin.children
        nodes = node.children
        data = []
        for node in nodes:
            data.append(node.toDict())
        return data
    else:
        return None

def create_top_folder(db_client, name):
    '''创建顶级目录'''
    tree_key = Folder.tree_key()
    tree_root = db_client.root[tree_key]
    r = PatchResolver('name')
    error = None
    data = None
    try:
        r.get(tree_root, name)
        error = '同名目录已存在'
    except ChildResolverError as e_cre:
        obj = Folder(name, parent=tree_root)
        tree_root._p_changed = True
        db_client.root._p_changed = True
        db_client.commit()
        data = obj.toDict()
    except ResolverError as e_re:
        pass
        print(e_re)
        error = 'unknown error'
    return (error, data)

def create_children_folder(db_client, name, parent):
    oid = Folder.id_hex2bin(parent)
    node = None
    try:
        node = db_client.connection.get(oid)
    except KeyError:
        pass
    error = None
    data = None
    if isinstance(node, Folder):
        r = PatchResolver('name')
        try:
            r.get(node, name)
            error = '同名目录已存在'
        except ChildResolverError as e_cre:
            obj = Folder(name, parent=node)
            node._p_changed = True
            db_client.root._p_changed = True
            db_client.commit()
            data = obj.toDict()
        except ResolverError as e_re:
            pass
            print(e_re)
            error = 'unknown error'
    else:
        error = '父级目录不存在'
    return (error, data)

################################################################################
@api_app.route('/folder/debug<:re:/?>', method=['GET'])
def folder_debug():
    DBC = request.environ.pop('DBC')
    output = debug_print_tree(DBC)
    # output = debug_check_tree(DBC)
    return '<pre><code>' + output + '</code></pre>'

def debug_check_tree(db_client):
    tree_key = Folder.tree_key()
    tree_root = db_client.root[tree_key]
    print('root: ', tree_root)
    r = PatchResolver('name')
    name = '新建目录'
    try:
        found = r.get(tree_root, name)
        print('found: ', found)
    except ChildResolverError as e_cre:
        print('ChildResolverError: ', e_cre)
    except ResolverError as e_re:
        print('ResolverError: ', e_re)
    return 'please watch terminal'

def debug_print_tree(db_client):
    tree_key = Folder.tree_key()
    tree_root = db_client.root[tree_key]
    from anytree import RenderTree
    output = []
    for pre, fill, node in RenderTree(tree_root):
        '''
        print('{0}{1} ==> {2} ==> {3}'.format(
            pre,
            node.name.decode('utf-8', 'ignore'),
            node.id_bin2hex(),
            node.get_hash()
        ))
        '''
        info = '{0}{1}'.format(
            pre,
            node.name.decode('utf-8', 'ignore')
        )
        print(info)
        output.append(info)
        # print(node.path)
    '''
    str_id = node.id_bin2hex()
    print(str_id)
    print(Folder.id_hex2bin(str_id))
    print(node._p_oid)
    print('-' * 80)
    '''
    return '\n'.join(output)